package com.rslai.base.tool.servertest.transport.command;

import com.alibaba.fastjson.JSON;
import com.rslai.base.tool.servertest.model.KeyValueStore;
import com.rslai.base.tool.servertest.model.ServiceDesc;
import com.rslai.base.tool.servertest.response.Response;
import com.rslai.base.tool.servertest.transport.http.HttpService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpExecuteCommand extends ExecuteCommand {
    protected static final Logger logger = LoggerFactory.getLogger(HttpExecuteCommand.class);
    private static final String SPLIT = "|";
    protected String url;
    protected String method;
    protected List<KeyValueStore> params;

    public HttpExecuteCommand(String id, String url, String method, String desc) {
        super(id, desc);
        this.url = url;
        this.method = method;
    }

    public Response execute(List<KeyValueStore> params) {
        Map headers = getHttpHeaders(params);
        this.params = removedHttpHeaders(params);

        if (logger.isInfoEnabled()) {
            logger.info("Http request start: url={}, method={}, headers={}, params={}", new Object[]{this.url, this.method, headers, getParamsAsString(this.params)});
        }
        HttpService.setHeaders(headers);

        Response response = null;
        if (isEntityRequest(this.method)) {
            this.method = fixMethod(this.method);
            response = HttpService.entityRequest(this.url, this.method, this.params);
        } else {
            response = HttpService.get(this.url, this.params);
        }

        if (logger.isInfoEnabled()) {
            logger.info("Http Execute : method={}, url={}, params={}, response={}", new Object[]{this.method, this.url, getParamsAsString(params), response});
        }
        return response;
    }

    private static List<KeyValueStore> splitParameters(List<KeyValueStore> params) {
        if (params == null) {
            return params;
        }
        List result = new ArrayList(params.size());
        for (KeyValueStore param : params) {
            Object value = param.getValue();
            if (((value instanceof String)) && (((String) value).contains("|"))) {
                String[] valueArray = StringUtils.split((String) value, "|");
                for (int i = 0; i < valueArray.length; i++)
                    result.add(new KeyValueStore(param.getName(), valueArray[i].trim()));
            } else {
                result.add(param);
            }
        }
        return result;
    }

    protected String fixMethod(String method) {
        if ("binary".equalsIgnoreCase(method)) {
            return "POST";
        }
        return method;
    }

    protected boolean isEntityRequest(String method) {
        return ("POST".equalsIgnoreCase(method)) || ("PUT".equalsIgnoreCase(method)) || ("binary".equalsIgnoreCase(method));
    }

    protected Map getHttpHeaders(List<KeyValueStore> params) {
        for (KeyValueStore param : params) {
            if (isHttpHeaders(param)) {
                return tryParseObject(param.getValue());
            }
        }
        return null;
    }

    protected String getParamsAsString(List<KeyValueStore> params) {
        if (params == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (KeyValueStore kv : params) {
            sb.append(kv.getName()).append("=").append(kv.getValue()).append("&");
        }

        return sb.toString();
    }

    protected List<KeyValueStore> removedHttpHeaders(List<KeyValueStore> params) {
        if (params == null) {
            return null;
        }
        List result = new ArrayList();
        for (KeyValueStore param : params) {
            if (!isHttpHeaders(param))
                result.add(param);
        }
        return result;
    }

    protected boolean isHttpHeaders(KeyValueStore param) {
        return param.getName().equalsIgnoreCase("http-headers");
    }

    protected String showReportUrlWithLink(String url, List<KeyValueStore> params) {
        if (!"get".equals(this.method)) return url;
        StringBuilder urlBuffer = new StringBuilder();
        urlBuffer.append("<a href=\"").append(url).append("?");
        if ((params != null) && (!params.isEmpty())) {
            for (KeyValueStore param : params) {
                urlBuffer.append(param.getName()).append("=").append(param.getValue()).append("&");
            }
            urlBuffer.deleteCharAt(urlBuffer.lastIndexOf("&"));
        }
        urlBuffer.append("\">").append(url).append("</a>");
        return urlBuffer.toString();
    }

    public String toReport() {
        return String.format("使用%s方式调用HTTP接口%s", new Object[]{StringUtils.isBlank(this.method) ? "get" : this.method, showReportUrlWithLink(this.url, this.params)});
    }

    public ServiceDesc desc() {
        return new ServiceDesc(this.id, this.url, this.desc);
    }

    /**
     * json字符串转map对象
     * @param value json字符串
     * @return Map
     */
    private static Map tryParseObject(Object value) {
        if (value instanceof String) {
            try {
                Map map = JSON.parseObject(value.toString());
                if (null == map) {
                    map = new HashMap();
                }
                return map;
            } catch (Exception e) {
                throw new RuntimeException(String.format("<%s>尝试转JSONObject失败, error message=%s", new Object[]{value, e.getMessage()}), e);
            }
        } else if (value instanceof Map) {
            return (Map) value;
        } else {
            throw new RuntimeException(String.format("<%s>返回map失败", new Object[]{value}));
        }
    }
}
